using System;
using System.Reflection;
using System.IO;
using System.Xml;
using System.Collections;
using SharpObjects.Configuration;
using System.Web;
using System.Messaging;
using SharpObjects.Configuration.ConfigurationProviders;
using SharpObjects.PathMapping;

namespace SharpObjects.Logging.LogTargets 
{
	public class PrivateMsmqLogTarget : LogTargetBase
	{
		protected string queueNameBase;
		protected string queueName;

		protected MessageQueue msmq = null;
		protected BinaryMessageFormatter messageFormatter = new BinaryMessageFormatter();
		protected bool recoverableMessages = true;

		protected static string hostName = System.Net.Dns.GetHostName();

		public PrivateMsmqLogTarget()
		{
		    this.queueNameBase = DefaultPathMapper.ApplicationName;
			CreateMutex(this.queueNameBase);

			this.queueName = string.Format("{0}\\Private$\\{1}", hostName, this.queueNameBase);
		}


		public PrivateMsmqLogTarget(string sQueueNameBase)
		{
			this.queueNameBase = sQueueNameBase;
			CreateMutex(this.queueNameBase);

			this.queueName = string.Format("{0}\\Private$\\{1}", hostName, this.queueNameBase);
		}

		protected string id = null;

        /*
                    <target id="MsmqTarget">
                        <queue_name_base>TestQueueLog</queue_name_base>
                        <recoverable_messages>true</recoverable_messages>
                    </target>

        */
        public void Initialize(XmlElement initializationElement)
		{

			IConfigurationProvider init = new XmlConfigurationProvider(initializationElement);
			this.id = init.GetString("@id");
			this.queueNameBase = init.GetString("queue_name_base", this.queueNameBase);
			this.queueName = string.Format("{0}\\Private$\\{1}", hostName, this.queueNameBase);
			this.recoverableMessages = init.GetBoolean("recoverable_messages", true);
			
		}


		protected void Open()
		{
			if(this.msmq == null)
			{
				if(!MessageQueue.Exists(this.queueName))
				{
					CreateNew();
				}

				this.msmq = new MessageQueue(this.queueName);
			}
		}

		protected override void Close()
		{
			if(this.msmq != null)
			{
				this.msmq.Close();
				this.msmq = null;
			}
		}

		protected void CreateNew()
		{
			MessageQueue mq = MessageQueue.Create(this.queueName, false);
			mq.Close();
		}
		
		protected override void WriteToLog(ILogEntry logEntry)
		{
			mutex.WaitOne();

			try
			{
				Open();

				if(this.msmq != null)
				{
					Message msg = new Message(logEntry, this.messageFormatter);
					msg.Recoverable = this.recoverableMessages;
					string label = CreateLabel(logEntry);
					this.msmq.Send(msg, label);
				}
			}
			catch(Exception exception)
			{
				Close();
                Log.AddErrorMessage(exception);
			}            

			mutex.ReleaseMutex();
		}

		protected string CreateLabel(ILogEntry logEntry)
		{
			string label = string.Format("{0} {1}", logEntry.Time.ToString("yyyy-MM-dd HH:mm:ss"), logEntry.Category);
			return label;
		}

		public override void Release() 
		{
			Close();
		}
	}
}
